package com.zoe.onelink.util;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Tuple;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.Collection;

/**
 * <p>标题: 路径匹配工具类</p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2021</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2021-08-05
 */
public class PathMatchUtil {

    /**
     * {@link AntPathMatcher} 线程安全
     */
    private static final PathMatcher PATH_MATCHER = new AntPathMatcher();

    private static final Cache<Tuple, Boolean> MATCH_RESULT_CACHE = CacheUtil.newLRUCache(10240);


    /**
     * 是否允许路径通过
     *
     * @param path               请求地址
     * @param onlyUrlList        包含地址
     * @param excludeUrlList     排除地址
     * @param matchedOnEmptyRule 当include和exclude配置都为空时,是否视为匹配成功
     * @return true=匹配成功 , false=匹配失败
     */
    public static boolean isPermit(String path,
                                   Collection<String> onlyUrlList,
                                   Collection<String> excludeUrlList,
                                   boolean matchedOnEmptyRule) {
        return isPermit(path, onlyUrlList, excludeUrlList, matchedOnEmptyRule, false, null);
    }

    /**
     * 是否允许路径通过
     *
     * @param path               请求地址
     * @param onlyUrlList        包含地址
     * @param excludeUrlList     排除地址
     * @param matchedOnEmptyRule 当include和exclude配置都为空时,是否视为匹配成功
     * @param useCache           是否使用缓存
     * @param group              缓存分组,不同的业务可能存在相同的path,所以增加分组标识来区分不同业务场景下的缓存
     * @return true=匹配成功 , false=匹配失败
     */
    public static boolean isPermit(String path,
                                   Collection<String> onlyUrlList,
                                   Collection<String> excludeUrlList,
                                   boolean matchedOnEmptyRule,
                                   boolean useCache,
                                   String group) {
        Tuple cacheKey;
        // 是否使用缓存模式
        if (useCache && group != null) {
            cacheKey = new Tuple(group, path);
            Boolean cached = MATCH_RESULT_CACHE.get(cacheKey);
            if (cached != null) {
                return cached;
            }
        } else {
            cacheKey = null;
        }

        // 开始进行匹配
        boolean isPermit;
        if (CollUtil.isNotEmpty(onlyUrlList)) {
            isPermit = onlyUrlList.stream().anyMatch(urlPattern -> PATH_MATCHER.match(urlPattern, path));
        } else if (CollUtil.isNotEmpty(excludeUrlList)) {
            isPermit = excludeUrlList.stream().noneMatch(urlPattern -> PATH_MATCHER.match(urlPattern, path));
        } else {
            isPermit = matchedOnEmptyRule;
        }

        // 缓存匹配结果
        if (cacheKey != null) {
            MATCH_RESULT_CACHE.put(cacheKey, isPermit);
        }
        return isPermit;
    }

    /**
     * 清空路径匹配缓存
     */
    public static void clearCache() {
        MATCH_RESULT_CACHE.clear();
    }

}
